home *** CD-ROM | disk | FTP | other *** search
/ STraTOS 1997 April & May / STraTOS 1 - 1997 April & May.iso / CD01 / INTERNET / BROWSERS / GLUESTIK.ZOO / memdemon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-27  |  5.2 KB  |  221 lines

  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <osbind.h>
  4. #include "global.h"
  5.  
  6. #define POOLSIZE_DEFAULT    50000L
  7. #define POOLSIZE_VAR        "ALLOCMEM"
  8. #define MIN_CHUNK        (sizeof(chunk_header) + 8)
  9. #define ALLOCED            0xAB000000UL
  10. #define FREED            0xFB000000UL
  11.  
  12. #define round(n)        (((n) + 7) & ~7)
  13. #define is_alloced(H)        (((H)->size & 0xFF000000L) == ALLOCED)
  14. #define is_freed(H)        (((H)->size & 0xFF000000L) == FREED)
  15. #define chunksize(H)        ((H)->size & 0x00FFFFFFL)
  16.  
  17. typedef struct chunk_header {
  18.   struct chunk_header *next;
  19.   unsigned long size;
  20. } chunk_header;
  21.  
  22. unsigned char *pool = 0;
  23. unsigned long poolsize = POOLSIZE_DEFAULT;
  24. static chunk_header *arena;
  25.  
  26. int init_mem(void)
  27. {
  28.   register char *s = do_getvstr(POOLSIZE_VAR);
  29.  
  30.   if (s)
  31.     poolsize = strtoul(s, NULL, 0);
  32.   if (poolsize <= MIN_CHUNK) {
  33.     Cconws("alloc pool size too small - using default size\r\n");
  34.     poolsize = POOLSIZE_DEFAULT;
  35.   }
  36.   pool = (unsigned char *)Mxalloc(poolsize, 0x2B); /* global, prefer TT RAM */
  37.   if (!pool) {
  38.     Cconws("Unable to allocate alloc pool\r\n");
  39.     return 0;
  40.   }
  41.   arena = (chunk_header *)pool;
  42.   arena->next = 0;
  43.   arena->size = (poolsize - sizeof(chunk_header)) | FREED;
  44.   return 1;
  45. }
  46.  
  47. /* join_next() -- Joins chunk |H| with the next block and sets its state to
  48.    |state|.  WARNING:  Assumes |H->next| is not NULL. */
  49. static void join_next(register chunk_header *H, unsigned long state)
  50. {
  51.   register chunk_header *H2 = H->next;
  52.   H->next = H2->next;
  53.   H->size = (chunksize(H) + chunksize(H2) + sizeof(chunk_header)) | state;
  54. }
  55.  
  56. /* try_split() -- split chunk |block| into two chunks, the first of size
  57.    |newsize|, if there's room for a second chunk.  The new chunk (if
  58.    any) is marked FREED; the (possibly smaller) original block is marked
  59.    ALLOCED.  WARNING:  assumes |newsize| is already round()'ed. */
  60. static void try_split(chunk_header *block, unsigned long newsize)
  61. {
  62.   register chunk_header *H;
  63.  
  64.   if (chunksize(block) - newsize >= MIN_CHUNK) {
  65.     H = (chunk_header *)((unsigned char *)(block + 1) + newsize);
  66.     H->next = block->next;
  67.     H->size = (chunksize(block) - newsize - sizeof(chunk_header)) | FREED;
  68.     block->next = H;
  69.     block->size = newsize | ALLOCED;
  70.  
  71.     /* if the next block is free, merge the new block into it */
  72.     if (H->next && is_freed(H->next))
  73.       join_next(H, FREED);
  74.   } else {
  75.     block->size = chunksize(block) | ALLOCED;
  76.   }
  77. }
  78.  
  79. char* do_KRmalloc(int32 size)
  80. {
  81.   register chunk_header *H;
  82.  
  83.   size = round(size);
  84.   if (size >= 0x01000000L || size == 0) {
  85. #ifdef DEBUG
  86.     debug("sls", "KRmalloc(", size, ") returns 0");
  87. #endif
  88.     return 0;
  89.   }
  90.  
  91.   for (H = arena; H; H = H->next) {
  92.     if (!is_freed(H) || chunksize(H) < size)
  93.       continue;
  94.     try_split(H, size);
  95. #ifdef DEBUG
  96.     debug("slsp", "KRmalloc(", size, ") returns ", (void *)(H+1));
  97. #endif
  98.     return (char *)(H + 1);
  99.   }
  100. #ifdef DEBUG
  101.   debug("sls", "KRmalloc(", size, ") returns 0");
  102. #endif
  103.   return 0;
  104. }
  105.  
  106. void do_KRfree(void *mem)
  107. {
  108.   register chunk_header *H = (chunk_header *)mem;
  109.  
  110. #ifdef DEBUG
  111.   debug("sps", "in KRfree(", mem, ")");
  112. #endif
  113.   if (!mem)
  114.     return;
  115.   H--;        /* step back to the header */
  116.   if (!is_alloced(H)) {
  117. #ifdef DEBUG
  118.     debug("s", "\tblock not alloced?");
  119. #endif
  120.     return;
  121.   }
  122.  
  123.   H->size = chunksize(H) | FREED;
  124.  
  125.   if (H->next && is_freed(H->next)) {
  126.     /* next block is free; merge with it */
  127.     join_next(H, FREED);
  128.   }
  129.  
  130.   if (H != arena) {
  131.     /* there is a previous chunk; merge with it if it's freed */
  132.     register chunk_header *H2;
  133.  
  134.     for (H2 = arena; H2 && H2->next != H; H2 = H2->next)
  135.       continue;
  136.     if (!H2) {    /* this shouldn't happen */
  137. #ifdef DEBUG
  138.       debug("s", "\tno previous block?");
  139. #endif
  140.       return;
  141.     }
  142.     if (is_freed(H2)) {
  143.       join_next(H2, FREED);
  144.       H = H2;
  145.     }
  146.   }
  147. #ifdef DEBUG
  148.   debug("s", "\tdone");
  149. #endif
  150. }
  151.  
  152. int32 do_KRgetfree(int16 flag)
  153. {
  154.   register chunk_header *H;
  155.   register unsigned long size = 0;
  156.  
  157. #ifdef DEBUG
  158.   debug("s", "in KRgetfree()");
  159. #endif
  160.   if (flag) {
  161.     for (H = arena; H; H = H->next) {
  162.       if (is_freed(H) && chunksize(H) > size)
  163.     size = chunksize(H);
  164.     }
  165.   } else {
  166.     for (H = arena; H; H = H->next) {
  167.       if (is_freed(H))
  168.     size += chunksize(H);
  169.     }
  170.   }
  171.   return size;
  172. }
  173.  
  174. char* do_KRrealloc(char *mem, int32 newsize)
  175. {
  176.   register chunk_header *H = (chunk_header *)mem;
  177.  
  178. #ifdef DEBUG
  179.   debug("s", "in KRrealloc()");
  180. #endif
  181.   if (!mem) {
  182.     mem = do_KRmalloc(newsize);
  183.     if (mem)
  184.       memset(mem, 0, newsize);
  185.     return mem;
  186.   }
  187.  
  188.   if (newsize == 0) {
  189.     do_KRfree(mem);
  190.     return 0;
  191.   }
  192.  
  193.   H--;        /* step back to the header */
  194.   if (!is_alloced(H))
  195.     return 0;
  196.  
  197.   newsize = round(newsize);
  198.   if (newsize <= chunksize(H)) {
  199.     /* if we're downsizing, we may have room to split the chunk */
  200.     try_split(H, newsize);
  201.     return mem;
  202.   } else if (H->next && is_freed(H->next) &&
  203.              (chunksize(H) + chunksize(H->next) +
  204.                     sizeof(chunk_header)) >= newsize) {
  205.     /* Next chunk is free and big enough to accommodate the new size;
  206.        join it with the current chunk */
  207.     join_next(H, ALLOCED);
  208.     /* We may even have room to split off part of the newly joined chunk */
  209.     try_split(H, newsize);
  210.     return mem;
  211.   } else {
  212.     register char *newmem = do_KRmalloc(newsize);
  213.  
  214.     if (!newmem)
  215.       return 0;
  216.     memcpy(newmem, mem, chunksize(H));
  217.     do_KRfree(mem);
  218.     return newmem;
  219.   }
  220. }
  221.